﻿using System;
using System.IO;
using System.Net;
using System.Threading;
using HK.Core.IO;
using HK.Core.Network.Download.Protocol.Control;
using HK.Core.Network.Download.Protocol.Data;
using HK.Core.Threader.Protocol;
using HK.Core.Utils;
using HThreader = HK.Core.Threader.Threader;

namespace HK.Core.Network.Download.Control
{
    /// <summary>
    /// 下载器
    /// </summary>
    public sealed class Downloader : HThreader, IDownloader
    {

#region Create

        /// <summary>
        /// 创建下载器
        /// </summary>
        /// <param name="iIndex">下载器索引</param>
        /// <param name="iOnCompleted">下载完成回调</param>
        /// <param name="iOptions">下载选项</param>
        /// <param name="iDecompressed">解密/解压回调</param>
        /// <param name="iRetry">重试次数</param>
        /// <param name="iMoveFile">移动文件标志位</param>
        /// <param name="iBufferSize">缓存大小</param>
        /// <param name="iTimeout">下载超时(单位:秒，默认:30秒)</param>
        /// <param name="iPriority">下载优先级</param>
        /// <returns>下载器</returns>
        public static IDownloader Create(int iIndex, DownloaderCompleted iOnCompleted, 
	        int iOptions = (int)DownloadOptions.ResFullDownload, DownloadDecompressed iDecompressed = null, 
	        int iRetry = 3, bool iMoveFile = false, int iBufferSize = 2048, int iTimeout = 30,
            ThreadPriority iPriority = ThreadPriority.Normal)
        {
            var downloader = new Downloader
            {
                Index = iIndex, Completed = iOnCompleted, DoDecompressed = iDecompressed, BufferSize = iBufferSize, 
                MoveFile = iMoveFile, TimeOut = iTimeout, RetryMaxNum = iRetry, Options = iOptions, Priority = iPriority
            };
            return downloader.Init() ? downloader : null;
        }
        
#endregion

        /// <summary>
        /// 保护构造函数
        /// </summary>
        private Downloader() {}
        
        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="iCurrent">当前执行</param>
        /// <param name="iPrev">执行前预处理</param>
        /// <param name="iNext">执行后处理</param>
        /// <returns>true:OK; false:NG;</returns>
        protected override bool Init(
            ThreadCurOperation iCurrent = null,
            ThreadPrevOperation iPrev = null,
            ThreadNextOperation iNext = null)
        {
	        
            Target = null;
            // 初始化完成，则切换到空闲状态
            State = DownloadState.Ok;

            Stopped = false;
            Paused = false;
            Canceled = false; 

            // 若没有开启下载失败重试功能，则默认为1次下载
            if (!Retry)
            {
	            RetryMaxNum = 1;
            }
            
            // 初始化操作
            InitOperations(iCurrent, iPrev, iNext);
            Initialized = true;
            
            return true;
        }
        
        /// <summary>
        /// 取得线程执行器名
        /// </summary>
        /// <returns>线程执行器名</returns>
        public override string GetThreaderName()
        {
            return $"Downloader_{Index}";
        }

        /// <summary>
        /// 索引
        /// </summary>
        public int Index { get; private set; } = -1;
        
#region State

		private DownloadState _state = DownloadState.None;
		/// <summary>
		/// 状态
		/// </summary>
		public DownloadState State
		{
			get => _state;
			private set
			{
				_state = value;
				if (DownloadState.Ok != _state)
				{
					int i = 0;
				}
			}
		}

        /// <summary>
        /// 状态描述
        /// </summary>
        public string StateDesc { get; private set; } = null;

#endregion
        
#region Options

        /// <summary>
        /// 校验选项
        /// </summary>
        public int Options { get; private set; } = (int)DownloadOptions.ResFullDownload;
        
        /// <summary>
        /// 覆盖重写
        /// <para>* true : 若该文件已经在下载/加载目录种存在，则强制删除。</para>
        /// <para>* false : 不删除</para>
        /// <para>* 该状态设定与断点续载有关</para>
        /// </summary>
        private bool _overWrite = true;
        private bool _lastOverWrite = false;
        
        /// <summary>
        /// 开启线程下载
        /// </summary>
        public bool UseThread => UtilsBytes.CheckBytes(Options, (int)DownloadOptions.UseThread);

        /// <summary>
        /// 重试标志位
        /// </summary>
        public bool Retry => UtilsBytes.CheckBytes(Options, (int)DownloadOptions.Retry);

        private int _retryMaxNum = 1;
        /// <summary>
        /// 重试上限数
        /// </summary>
        public int RetryMaxNum
        {
	        get => _retryMaxNum;
	        private set
	        {
		        _retryMaxNum = value;
		        if (0 >= _retryMaxNum)
		        {
			        _retryMaxNum = 1;
		        }
		        RetryCount = _retryMaxNum;
	        }
        }

        /// <summary>
        /// 重试数
        /// </summary>
        public int RetryCount { get; private set; } = 0;
        
        /// <summary>
        /// 文件大小校验
        /// </summary>
        public bool SizeCheck => UtilsBytes.CheckBytes(Options, (int)DownloadOptions.SizeCheck);
        
        /// <summary>
        /// 目标目录存在校验
        /// <para>* 若目标目录不存在，则自动创建</para>
        /// </summary>
        public bool DstDirExistCheck => UtilsBytes.CheckBytes(Options, (int)DownloadOptions.DstDirExistCheck);

        /// <summary>
        /// 校验标志位 - Crc
        /// </summary>
        public bool CrcCheck => UtilsBytes.CheckBytes(Options, (int)DownloadOptions.CrcCheck);

        /// <summary>
        /// 校验标志位 - Md5
        /// </summary>
        public bool Md5Check => UtilsBytes.CheckBytes(Options, (int)DownloadOptions.Md5Check);
        
        /// <summary>
        /// 解压/解密
        /// </summary>
        public bool Decompressed => UtilsBytes.CheckBytes(Options, (int)DownloadOptions.Decompressed);
        
        /// <summary>
        /// 缓存大小
        /// <para>* 下载时单次写入的缓存大小。单位:Byte。默认:2048</para>
        /// </summary>
        public int BufferSize { get; private set; } = 2048;

        private int _timeOut = 0;
        /// <summary>
        /// 超时(单位:秒)
        /// </summary>
        public int TimeOut
        {
	        get => _timeOut;
	        private set
	        {
		        _timeOut = value;
		        _readWriteTimeOut = value * 1000;
		        _timeOutWait = _readWriteTimeOut * 2;
	        }
        }
        
        /// <summary>
        /// 超时等待(单位:毫秒)
        /// </summary>
        private int _timeOutWait = 0;
        
        /// <summary>
        /// 读写超时(单位:毫秒)
        /// </summary>
        private int _readWriteTimeOut = 0;

        /// <summary>
        /// 移动文件标志位
        /// <para>* true:下载完毕，将文件从临时下载目录移动到目标目录;</para>
        /// </summary>
        public bool MoveFile { get; private set; } = false;

        /// <summary>
        /// 解压/解密方式
        /// </summary>
        public DecodeType Decode { get; private set; } = DecodeType.Jab;
        
#endregion
        
#region Info

        /// <summary>
        /// 下载目标信息
        /// </summary>
        public IDownloadInfo Target { get; private set; } = null;

        /// <summary>
        /// 下载Url
        /// </summary>
        public string DownloadUrl => Target?.Url;

        /// <summary>
        /// 已下载完成的大小
        /// <para>* 单位 : Byte</para>
        /// </summary>
        public long DownloadedSize { get; private set; } = 0L;

        /// <summary>
        /// 总共大小
        /// <para>* 单位 : Byte</para>
        /// </summary>
        public long TotalSize 
        {
	        get => Target?.Size ?? 0L;
	        private set
	        {
		        if (null != Target)
		        {
			        Target.Size = value;
		        }
	        }
        }
        
        /// <summary>
        /// 文件名
        /// </summary>
        public string FileName => Target?.FileName;

        /// <summary>
        /// 保存路径
        /// <para>* 该路径为，下载临时保存路径。下载成功并通过文件校验后，将拷贝到真正的保存路径。即:SavePath</para>
        /// </summary>
        public string DownloadPath => Target?.DownloadPath;
        
        /// <summary>
        /// 保存路径
        /// </summary>
        public string SavePath => Target?.SavePath;
        
        /// <summary>
        /// 校验码 - Crc
        /// </summary>
        public long CrcCheckCode => Target?.CrcCheckCode ?? -1L;
        
        /// <summary>
        /// 校验码 - Md5
        /// </summary>
        public string Md5CheckCode => Target?.Md5CheckCode;

        /// <summary>
        /// 重置下载目标信息
        /// </summary>
        /// <param name="iTarget">目标信息</param>
        /// <param name="iForceContinue">强制继续进行</param>
        /// <returns>true:OK; false:Ng;</returns>
        private bool ResetTarget(IDownloadInfo iTarget, bool iForceContinue = false)
        {
            if (null == iTarget || !iTarget.Valid)
            {
                Error("ResetTarget():The target info is null or invalid!");
                return false;
            }

            if (!iForceContinue && Executing)
            {
                Error("ResetTarget():The downloader is still running!(Index:{0})", Index);
                return false;
            }
            
            Target = iTarget;
            Target.Downloading = true;
            State = DownloadState.Ok;
            DownloadedSize = 0L;
            _overWrite = true;
            RetryCount = RetryMaxNum;
            
            // 线程相关状态
            Stopped = false;
            Paused = false;
            Canceled = false;
            Interrupted = false;
            return true;
        }

#endregion
        
#region Events

        /// <summary>
        /// 完成回调
        /// </summary>
        public DownloaderCompleted Completed { get; private set; } = null;
        
        /// <summary>
        /// 解压/解密回调
        /// </summary>
        public DownloadDecompressed DoDecompressed { get; private set; } = null;

        /// <summary>
        /// 执行失败操作
        /// </summary>
        /// <param name="iState">状态</param>
        /// <param name="iDesc">描述</param>
        /// <param name="iTag">Tag</param>
        private void DoFailed(DownloadState iState, string iDesc, string iTag = null)
        {
	        if(DownloadState.Ok == iState) return;
	        
	        State = iState;
	        var message = $"{iState}";
	        if (!string.IsNullOrEmpty(iDesc))
	        {
		        message = $"{message} - {iDesc}";
	        }
	        StateDesc = $"Index:{Index} {message}";

	        if (!string.IsNullOrEmpty(iTag))
	        {
		        message = $"{iTag}:{message}";
	        }
	        
	        Error(message);
	        Completed?.Invoke(State, this, StateDesc);
	        
        }

#endregion

#region Download

		/// <summary>
		/// 开始下载
		/// </summary>
		/// <param name="iTarget">下载目标信息</param>
		/// <returns>true:OK; false:Ng;</returns>
		public bool Start(IDownloadInfo iTarget)
        {
	        // 重置下载信息
	        if (!ResetTarget(iTarget))
	        {
		        DoFailed(DownloadState.Failed, iTarget.ToString(), "Start");
		        return false;
	        }
	        Info("Start():Index:{0} Target:{1} Url:{2} Retry:{3}/{4} Code:{5} Desc:{6}",
		        Index, FileName, DownloadUrl, RetryCount, RetryMaxNum, State, StateDesc);

	        //this.Error("Start():Index:{0} - {1}", Index, iTarget.FileName);
	        
            // 执行下载
            Execute(Completed);

            return true;
        }
        
        /// <summary>
        /// 执行
        /// </summary>
        /// <param name="iOnCompleted">下载完成回调</param>
        private void Execute(DownloaderCompleted iOnCompleted)
        {
	        // 线程执行
	        if (UseThread)
	        {
		        Execute();
	        }
	        else
	        {

		        // 执行操作
		        if (!CurOperation.Invoke())
		        {
			        DoFailed(State, $"{StateDesc}\nTarget:{FileName} Retry:{RetryCount}/{Retry}", "Execute");
		        }
		        else
		        {
			        // 回调函数
			        // 非中断
			        if (!Interrupted)
			        {
				        iOnCompleted?.Invoke(State, this, StateDesc);
			        }
		        }
		        
		        // 执行完成
		        Stopped = true;
		        Executing = false;
	        }
        }

        /// <summary>
        /// 执行前预处理
        /// </summary>
        /// <returns>true:待机，进入睡眠状态; false:中止待机，继续向下执行;</returns>
        protected override bool PrevExecute()
        {
	        if (base.PrevExecute()) return true;
	        // 目标信息为null或者无效，则挂起并进入睡眠状态
	        return null == Target || !Target.Valid;
        }

        /// <summary>
        /// 线程当前处理
        /// </summary>
        /// <returns>true:执行成功; false:执行失败;</returns>
        protected override bool CurExecute()
        {
	        Info("CurExecute():Url:{0}", DownloadUrl);
	        
	        var flg = false;
	        while (0 < RetryCount)
	        {
		        
		        // 若中途被取消了
		        if (Canceled) break;
		        
		        // 若被中断
		        if (Interrupted) break;
		        
		        // 写入文件
		        State = WriteToFile(DownloadUrl, DownloadPath, SavePath);
		        
		        // 下载成功，则返回
		        if (DownloadState.Ok == State)
		        {
			        // 消耗时间监控
			        TimeWatch.Stop();
			        CostTime = TimeWatch.ElapsedMilliseconds;
			        Target.CostTime = CostTime;
			        flg = true;
			        break;
		        }
		        
		        // 下载一次失败，文件切换为覆盖模式，以便删除原有残余文件
		        _lastOverWrite = _overWrite;
		        _overWrite = true;
                
		        // 未执行成功，则等待10秒后，重试
		        Thread.Sleep(10000);
		        --RetryCount;
					
		        Error("CurExecute():Index:{0} OverWrite:{1} Target:{2} Retry:{3}/{4} State:{5} Desc:{6}",
			        Index, _overWrite, FileName, RetryCount, RetryMaxNum, State, StateDesc);
	        }
	        
	        _overWrite = _lastOverWrite;
	        return flg;
        }

        /// <summary>
        /// 写入文件
        /// </summary>
        /// <param name="iUrl">文件下载地址</param>
        /// <param name="iDownloadPath">下载路径</param>
        /// <param name="iSavePath">保存路径</param>
        /// <returns>下载状态</returns>
        private DownloadState WriteToFile(string iUrl, string iDownloadPath, string iSavePath)
        {
	        HttpWebRequest req = null;

	        try
			{
				// 覆盖重写，则删除原来存在的文件
				if (_overWrite)
				{
					UtilsIo.DeleteFile(iDownloadPath);
				}
				
				// 使用流操作文件
				using (var fs = new FileStream(iDownloadPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
				{
					// 获取文件现在的长度(支持断点续载)
					DownloadedSize = fs.Length;
                    
					req = HttpWebRequest.Create(iUrl) as HttpWebRequest;
					if (null == req)
					{
						DoFailed(DownloadState.NetworkErr, $"HttpWebRequest.Create() Failed!(URL:{iUrl})", "WriteToFile");
					}

					if (null != req && DownloadState.Ok == State)
					{
						req.Method = "GET";
					
						// 超时时间设置
						req.ReadWriteTimeout = _readWriteTimeOut;
						req.Timeout = _timeOutWait;
						req.KeepAlive = true;

						// 断点续传核心，设置远程访问文件流的起始位置
						req.AddRange((int) DownloadedSize);

						using (var rsp = req.GetResponse() as HttpWebResponse)
						{
							if (null == rsp)
							{
								DoFailed(DownloadState.NetworkErr, $"HttpWebRequest.GetResponse() Failed!(URL:{iUrl})",
									"WriteToFile");
							}
							else
							{
								// 请求OK或者断点续传请求OK
								if (HttpStatusCode.OK != rsp.StatusCode &&
								    HttpStatusCode.PartialContent != rsp.StatusCode)
								{
									DoFailed(DownloadState.NetworkErr, 
										$"HttpWebRequest.GetResponse() Failed!(URL:{iUrl} Code:{rsp.StatusCode})", 
										"WriteToFile");
								}
							}
						
							// 当前状态为成功或者可以继续尝试的场合
							if (DownloadState.Ok == State)
							{
								Info("WriteToFile():Succeeded:{0} OverWrite：{1} Size:{2} Bytes",
									Succeeded, _overWrite, TotalSize);
                        
								//如果没下载完
								if (DownloadedSize < TotalSize)
								{
									// 断点续传核心，设置本地文件流的起始位置
									fs.Seek(DownloadedSize, SeekOrigin.Begin);
						
									// 写入文件
									DownloadFileByHttp(rsp, fs);
								}
							}
						}
					}
				}
			}
			catch (WebException webExp)
			{
				var targetDesc = Target.Url;
				var targetDataSize = UtilsMath.GetDataDisplaySize(Target.Size);
				var curCostTime = UtilsTime.ConvertToDisplayTime(TimeWatch.ElapsedMilliseconds, false, 2);
				targetDesc = $"{targetDesc}({targetDataSize} +{curCostTime})";
				
				DoFailed(DownloadState.WebException, 
					$"Retry:({RetryCount}/{RetryMaxNum}) - {targetDesc}\n {webExp.GetType().Name} - {webExp.Message}\n StackTrace:{webExp.StackTrace}", 
					"WriteToFile");
			}
			catch (Exception exp)
			{
				var targetDesc = Target.Url;
				var targetDataSize = UtilsMath.GetDataDisplaySize(Target.Size);
				var curCostTime = UtilsTime.ConvertToDisplayTime(TimeWatch.ElapsedMilliseconds, false, 2);
				targetDesc = $"{targetDesc}({targetDataSize} +{curCostTime})";
				
				DoFailed(DownloadState.Exception, 
					$"Retry:({RetryCount}/{RetryMaxNum}) - {targetDesc}\n {exp.GetType().Name} - {exp.Message}\n StackTrace:{exp.StackTrace}", 
					"WriteToFile");
			}
			finally
			{
				// 回复 + 请求
				req = null;

				var fileSizeCheck = false;
				// 下载成功，则移动文件到加载目录
				if (DownloadState.Ok == State)
				{
					// 校验文件Md5码
					if (Md5Check && !string.IsNullOrEmpty(Md5CheckCode))
					{
						// 取得下载文件的Md5码
						var downloadFileMd5 = UtilsIo.GenerateMd5OfFile(iDownloadPath, out var oLocalFileSize);
						if (!downloadFileMd5.Equals(Md5CheckCode))
						{
							DoFailed(DownloadState.CheckCodeNotMatch, 
								$"Idx:{Index} Download file check failed(Md5)!(Downloaded:{downloadFileMd5} CheckCode:{Md5CheckCode} Url:{iUrl})", 
								"WriteToFile");
						}

						if (SizeCheck)
						{
							if (oLocalFileSize != TotalSize)
							{
								DoFailed(DownloadState.FileSizeNotMatch, 
									$"Idx:{Index} The size of download file is not match!(Url:{iUrl} Size:T-{TotalSize}/L-{oLocalFileSize})", 
									"WriteToFile");
							}
							fileSizeCheck = true;
						}
					}
					
					// Crc文件校验
					if (CrcCheck && 0L < CrcCheckCode)
					{
						// 取得下载文件的Crc码
						var downloadCrcCode = UtilsIo.GenerateCRCByFile(iDownloadPath, out var oLocalFileSize);
						if (downloadCrcCode != CrcCheckCode)
						{
							DoFailed(DownloadState.CheckCodeNotMatch, 
								$"Idx:{Index} Download file check failed(Crc)!(Downloaded:{downloadCrcCode} CheckCode:{CrcCheckCode} Url:{iUrl})", 
								"WriteToFile");
						}
						if (!fileSizeCheck && SizeCheck)
						{
							if (oLocalFileSize != TotalSize)
							{
								DoFailed(DownloadState.FileSizeNotMatch, 
									$"Idx:{Index} The size of download file is not match!(Url:{iUrl} Size:T-{TotalSize}/L-{oLocalFileSize})", 
									"WriteToFile");
							}
							fileSizeCheck = true;
						}
					}

					if (!fileSizeCheck && SizeCheck)
					{
						var localFileSize = UtilsIo.GetFileSize(iDownloadPath);
						if (localFileSize != TotalSize)
						{
							DoFailed(DownloadState.FileSizeNotMatch, 
								$"Idx:{Index} The size of download file is not match!(Url:{iUrl} Size:T-{TotalSize}/L-{localFileSize})", 
								"WriteToFile");
						}
						fileSizeCheck = true;
					}

					// 需要移动目录的场合
					if (DownloadState.Ok == State)
					{
						// 移动文件
						if (MoveFile)
						{
							// 删除已又文件
							if(UtilsIo.MoveFile(iDownloadPath, iSavePath, true))
							{
								Info("WriteToFile():Index:{0} {1} -> {2}", Index, iDownloadPath, iSavePath);
							}
							else
							{
								DoFailed(DownloadState.MoveFileFailed, 
									$"Idx:{Index} MoveFile Failed!({iDownloadPath} -> {iSavePath})", 
									"WriteToFile");
							}
						}
						else
						{
							// 解压/解密
							if (Decompressed)
							{
								if (null == DoDecompressed)
								{
									// Jab解包
									if (!UtilsJab.Decode(iDownloadPath, iSavePath, BufferSize))
									{
										DoFailed(DownloadState.DecompressedFailed, 
											$"Idx:{Index} UtilsJab.Decode() Failed!\n  DownloadPath:{iDownloadPath}\n  SavePath:{iSavePath}", 
											"WriteToFile");
									}
									else
									{
										// 删除下载文件
										UtilsIo.DeleteFile(iDownloadPath);
									}
								}
								else
								{
									if (!DoDecompressed.Invoke(Target))
									{
										DoFailed(DownloadState.DecompressedFailed, 
											$"Idx:{Index} Decompressed Failed!(Url:{iUrl})", 
											"WriteToFile");
									}
								}
							}
						}
						
					}
					else
					{
						// 下载失败，则删除残存文件
						UtilsIo.DeleteFile(iDownloadPath);
					}
				}
			}
			
	        return State;
        }

        /// <summary>
        /// 下载文件
        /// </summary>
        /// <param name="iResponse">下载请求回复对象</param>
        /// <param name="iFs">文件</param>
        /// <returns>下载状态</returns>
        private DownloadState DownloadFileByHttp(HttpWebResponse iResponse, FileStream iFs)
        {
	        var st = iResponse.GetResponseStream();
	        if (null == st)
	        {
		        DoFailed(DownloadState.NetworkErr, 
			        $"Idx:{Index} GetResponseStream() Failed!", 
			        "WriteToFile");
		        return State;
	        }
	        // Error("DownloadFileByHttp():Index:{0} - {1}", Index, Target.FileName);

	        // 已失败
	        if (DownloadState.Ok != State) return State;
		        
	        // 写入缓存初始化
	        var buffer = new byte[BufferSize];

	        // 使用流读取内容到buffer中
	        // 注意方法返回值代表读取的实际长度,并不是buffer有多大，stream就会读进去多少
	        var length = st.Read(buffer, 0, buffer.Length);

	        // 循环写入
	        while (length > 0)
	        {
		        // 取消
		        if (Canceled)
		        {
			        DoFailed(DownloadState.Canceled, 
				        $"Idx:{Index} Downloaded had been canceled!", 
				        "WriteToFile");
			        break;
		        }

		        // 暂停
		        while (Paused)
		        {
			        // 取消
			        if (Canceled)
			        {
				        DoFailed(DownloadState.Canceled, 
					        $"Idx:{Index} Downloaded had been canceled!", 
					        "WriteToFile");
				        break;
			        }
									
			        // 等待500毫秒后，继续轮询暂停状态，直到恢复
			        Thread.Sleep(500);
		        }

		        // 已失败
		        if (DownloadState.Ok != State) break;

		        // 写入文件
		        UtilsIo.WriteToFile(iFs, buffer, length);

		        // 计算进度
		        DownloadedSize += length;
		        // 类似尾递归
		        length = st.Read(buffer, 0, buffer.Length);
	        }

	        buffer = null;
	        st = null;
	        return State;
        }
        
        /// <summary>
        /// 执行后处理
        /// </summary>
        /// <param name="iSucceed">执行成功标志位</param>
        /// <returns>true:继续执行; false:不用继续执行;</returns>
        protected override bool NextExecute(bool iSucceed)
        {
	        if (!base.NextExecute(iSucceed)) return false;
	        // 下载完成
	        Target.Downloaded = true;
	        
	        // 若还存在补丁
	        var patch = Target.Patch;
	        if (null != patch && patch.Valid)
	        {
		        // 重置状态
		        return ResetTarget(patch, true);
	        }

	        // 完成回调
	        var nextTarget = Completed?.Invoke(State, this, StateDesc);
	        if (null == nextTarget || !nextTarget.Valid) return false;
            
	        // 重置状态
	        return ResetTarget(nextTarget, true);
        }

#endregion

		/// <summary>
		/// 线程正常结束
		/// </summary>
		protected override void OnFinished()
		{
			// Error("OnFinished():Index:{0} - Id:{1}", Index, Target.Id);
		}

        /// <summary>
        /// 释放
        /// </summary>
        public override void Dispose()
        {
            base.Dispose();
	        
            Target = null;
            Options = (int)DownloadOptions.None;
            MoveFile = false;

            _overWrite = true;
            _lastOverWrite = false;
            RetryMaxNum = 0;
            RetryCount = 0;
            BufferSize = 0;
            TimeOut = 0;
            DownloadedSize = 0L;
        }
    }
}
